package blue.http.internal.core.handler.parameter;

import blue.http.core.annotation.BodyContent;
import blue.http.core.annotation.BodyJson;
import blue.http.core.annotation.BodyParam;
import blue.http.core.annotation.HttpCookie;
import blue.http.core.annotation.HttpHeader;
import blue.http.core.annotation.Multipart;
import blue.http.core.annotation.PathVariable;
import blue.http.core.annotation.QueryParam;
import blue.http.core.message.HttpRequest;
import blue.http.core.message.UploadFile;
import blue.http.core.message.WebSocketRequest;
import blue.http.internal.core.parser.RequestParamConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;
import java.util.Map;

/**
 * @author Jin Zheng
 * @since 2020-01-11
 */
public class ParameterDispatcher {
	private static Logger logger = LoggerFactory.getLogger(ParameterDispatcher.class);

	private final Map<Class<?>, ParamHandler> annotationMap = new HashMap<>();
	private final Map<Class<?>, ParamHandler> typeMap = new HashMap<>();

	public ParameterDispatcher() {
		// annotation
		annotationMap.put(BodyContent.class, new BodyContentParamHandler());
		annotationMap.put(BodyJson.class, new BodyJsonParamHandler());
		annotationMap.put(BodyParam.class, new BodyParamParamHandler());
		annotationMap.put(HttpCookie.class, new HttpCookieParamHandler());
		annotationMap.put(HttpHeader.class, new HttpHeaderParamHandler());
		annotationMap.put(Multipart.class, new MultipartParamHandler());
		annotationMap.put(PathVariable.class, new PathVariableParamHandler());
		annotationMap.put(QueryParam.class, new QueryParamParamHandler());

		// type
		typeMap.put(String.class, new StringParamHandler());
		typeMap.put(UploadFile.class, new UploadFileParamHandler());
		typeMap.put(HttpRequest.class, new HttpRequestParamHandler());
		typeMap.put(WebSocketRequest.class, new WebSocketRequestParamHandler());

	}

	public Object handleParam(RequestParamConfig config, Object request) {
		if (config.hasParamAnnotation()) {
			ParamHandler handler = annotationMap.get(config.getParamAnnotationClazz());
			this.check(handler, config.getParamAnnotationClazz());
			return handler.handle(config, request);
		}
		ParamHandler handler = typeMap.get(config.getParamClazz());
		this.check(handler, config.getParamClazz());
		return handler.handle(config, request);
	}

	private void check(ParamHandler handler, Class<?> clazz) {
		if (handler == null) {
			throw new NullPointerException("ParamHandler is null, class: " + clazz.getName());
		}
	}

}
